package cn.bugstack.springframework.beans.factory.support;

import cn.bugstack.springframework.beans.BeansException;
import cn.bugstack.springframework.beans.factory.ConfigurableListableBeanFactory;
import cn.bugstack.springframework.beans.factory.DisposableBean;
import cn.bugstack.springframework.beans.factory.config.BeanDefinition;

import java.util.*;

/**
 *
 *
 *
 * 作者：DerekYRC https://github.com/DerekYRC/mini-spring
 * @description 默认的Bean工厂实现类
 * @date 2022/03/07
 *
 *
 */
/**
 * 默认可列表 Bean 工厂类，继承自 AbstractAutowireCapableBeanFactory 并实现 BeanDefinitionRegistry 接口。
 * 这个类主要负责管理 Bean 定义，包括获取和注册 Bean 定义。
 */
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory implements BeanDefinitionRegistry , ConfigurableListableBeanFactory {

    // 存储 Bean 定义的映射，键为 Bean 名称，值为 Bean 定义。
    private Map<String, BeanDefinition> beanDefinitionMap = new HashMap<>();


    /**
     * 获取指定名称的 Bean 定义。
     *
     * @param beanName 要获取 Bean 定义的 Bean 名称。
     * @return 返回对应的 Bean 定义。
     * @throws BeansException 如果没有找到指定名称的 Bean 定义。
     */
    @Override
    public BeanDefinition getBeanDefinition(String beanName) {
        BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
        if (beanDefinition == null) throw new BeansException("No bean named '" + beanName + "' is defined");
        return beanDefinition;
    }

    @Override
    public void preInstantiateSingletons() throws BeansException {
        beanDefinitionMap.keySet().forEach(item -> getBean(item));
    }

    /**
     * 注册一个 Bean 定义到工厂中。
     *
     * @param beanName 要注册的 Bean 的名称。
     * @param beanDefinition 要注册的 Bean 的定义。
     */
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
        beanDefinitionMap.put(beanName, beanDefinition);
    }

    /**
     * 从bean定义映射中移除指定名称的bean定义。
     * 如果给定的bean名称存在，则移除对应的bean定义；否则，抛出BeansException异常。
     *
     * @param beanName 要移除的bean的名称。
     * @throws BeansException 如果给定的bean名称不存在于bean定义映射中。
     */
    @Override
    public void removeBeanDefinition(String beanName) throws BeansException {
        // 检查beanName是否存在于bean定义映射中，如果存在，则移除；如果不存在，抛出异常
        if (beanDefinitionMap.containsKey(beanName)) {
            beanDefinitionMap.remove(beanName);
        }
        else {
            throw new BeansException(beanName + " maybe error, it not have bean definition");
        }
    }



    /**
     * 检查给定的bean名称是否在bean定义映射中存在。
     *
     * @param beanName 待检查的bean名称。
     * @return 如果bean名称存在于bean定义映射中，则返回true；否则返回false。
     */
    @Override
    public boolean containsBeanDefinition(String beanName) {
        // 利用bean定义映射的containsKey方法，检查beanName是否存在
        return beanDefinitionMap.containsKey(beanName);
    }


    /**
     * 获取所有bean定义的名称数组。
     * 这个方法重写了接口方法，用于返回当前环境中所有bean定义的名称。
     *
     * @return String[] 包含所有bean定义名称的字符串数组。
     */
    @Override
    public String[] getBeanDefinitionNames() {
        // 将bean定义名称的集合转换为字符串数组并返回
        return beanDefinitionMap.keySet().toArray(new String[0]);
    }

    /**
     * 获取当前 Bean 定义的数量。
     * 这个方法重写了接口方法，用于返回注册在容器中的 Bean 定义的数量。
     *
     * @return int 返回 Bean 定义的数量。
     */
    @Override
    public int getBeanDefinitionCount() {
        return beanDefinitionMap.size();
    }


    /**
     * 检查给定的bean名称是否已被使用。
     *
     * @param beanName 待检查的bean名称。
     * @return 如果给定的bean名称在bean定义映射中存在，则返回true；否则返回false。
     */
    @Override
    public boolean isBeanNameInUse(String beanName) {
        // 检查bean定义映射中是否包含给定的bean名称
        return beanDefinitionMap.containsKey(beanName);
    }


    /**
     * description: 这段代码是一个 Spring 容器的方法，用于获取 指定类型的 所有 bean 实例，
     * 并以 bean 的名称为键，实例为值，存储在一个 Map 中返回。
     *
     * @author: aaZhao
     * @date: 2024/3/22 22:29
     */
    @Override
    public <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException {
        // 创建一个空的 HashMap 对象 result，用于存储满足条件的 bean。
        Map<String, T> result = new HashMap<>();
        beanDefinitionMap.forEach((beanName, beanDefinition) -> {
            Class beanClass = beanDefinition.getBeanClass();
            // type.isAssignableFrom(beanClass) 和 beanClass.isAssignableFrom(type) 是不同的，它们之间的差异在于检查的方向。
            // type.isAssignableFrom(beanClass): 这个方法检查 type 是否是 beanClass 的父类或接口。
            // 换句话说，它检查的是 beanClass 是否可以赋值给 type，也就是 type 是否能够容纳 beanClass 的实例。
            if (type.isAssignableFrom(beanClass)) {
                result.put(beanName, (T) getBean(beanName));
            }
        });
        return result;
    }

    @Override
    public <T> T getBean(Class<T> requiredType) throws BeansException {
        List<String> beanNames = new ArrayList<>();
        for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
            Class beanClass = entry.getValue().getBeanClass();
            if (requiredType.isAssignableFrom(beanClass)) {
                beanNames.add(entry.getKey());
            }
        }
        if (1 == beanNames.size()) {
            return getBean(beanNames.get(0), requiredType);
        }

        throw new BeansException(requiredType + "expected single bean but found " + beanNames.size() + ": " + beanNames);
    }

}

